#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__
#include "../mqcommon/mq_helper.hpp"
#include "../mqcommon/mq_msg.pb.h"

namespace zymq
{
    class Router 
    {
    public:
        static bool isLegalRoutingKey(const std::string &routing_key) 
        {
            //routing_key：只需要判断是否包含有非法字符即可， 合法字符( a~z, A~Z, 0~9, ., _)
            for (auto &ch : routing_key) 
            {
                if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
                    (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '.')) 
                {
                    continue;
                }

                return false;
            }
            return true;
        }

        static bool isLegalBindingKey(const std::string &binding_key) 
        {
            //1. 判断是否包含有非法字符， 合法字符：a~z, A~Z, 0~9, ., _, *, #
            for (auto &ch : binding_key) 
            {
                if ((ch >= 'a' && ch <= 'z') ||(ch >= 'A' && ch <= 'Z') ||
                    (ch >= '0' && ch <= '9') ||(ch == '_' || ch == '.') ||(ch == '*' || ch == '#')) 
                {
                    continue;
                }
                return false;
            }
            // * 和 # 必须独立存在
            std::vector<std::string> sub_words;
            StrHelper::split(binding_key, ".", sub_words);
            for(auto & word : sub_words)
            {
                // 单词长度大于一，且中间有通配符
                if(word.size() > 1 && 
                (word.find("*") != std::string::npos || word.find("#") != std::string::npos))
                    return false;
            }            
            // * 和 # 不能连续存在
            for(int i = 1; i < sub_words.size(); i++)
            {
                if(sub_words[i] == "#" && sub_words[i - 1] == "*") return false;
                if(sub_words[i] == "#" && sub_words[i - 1] == "#") return false;
                if(sub_words[i] == "*" && sub_words[i - 1] == "#") return false;
            }
            return true;
        }

        //空routing_key不应该匹配任何binding_key，这正是消息队列系统安全性和可靠性的体现。
        static bool route(ExchangeType type, const std::string &routing_key, const std::string &binding_key)
        {
            if(type == ExchangeType::DIRECT)
                return routing_key == binding_key;

            if(type == ExchangeType::FANOUT)
                return true;

            if(type == ExchangeType::TOPIC)
            {
                // binding作为行 routing作为列
                std::vector<std::string> binding_words, routing_words;
                int m = StrHelper::split(binding_key, ".", binding_words);
                int n = StrHelper::split(routing_key, ".", routing_words);

                std::vector<std::vector<bool>> dp(m + 1,std::vector<bool>(n + 1, false));
                dp[0][0] = true;

                // 如果binding_key以#开始，则将#对应行的第0列置为1
                if(binding_words[0] == "#")
                    dp[1][0] = true;

                for(int i = 1; i <= m; i++)
                {
                    for(int j = 1; j <= n; j++) 
                    {
                        // binding_words[i]和routing_words[j]相等 则从左上方继承
                        if(binding_words[i - 1] == routing_words[j - 1])
                            dp[i][j] = dp[i - 1][j - 1];

                        // 如果binding_words[i]是* 则和routing_words[j]随便匹配
                        if(binding_words[i - 1] == "*")
                            dp[i][j] = dp[i - 1][j - 1];

                        // 如果binding_word是# 则从左上圈继承
                        if(binding_words[i - 1] == "#")
                        {
                            // 情况1：匹配一个单词
                            if(dp[i - 1][j - 1])
                                dp[i][j] = true;

                            // 情况2：继续匹配更多单词
                            if(dp[i][j - 1])
                                dp[i][j] = true;

                            // 情况3：匹配零个单词
                            if(dp[i - 1][j])
                                dp[i][j] = true;
                        }
                    }
                }
                return dp[m][n];
            }

            return false;
        }
    };
}

#endif